package com.nhim.cms.admin.client.ctype.ui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.uibinder.client.UiTemplate;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.nhim.cms.admin.client.rpc.ContentTypeElementDefinitionRPCService;
import com.nhim.cms.admin.client.rpc.ContentTypeElementDefinitionRPCServiceAsync;
import com.nhim.cms.admin.shared.ContentTypeElementDefinitionRPCProxy;
import com.nhim.cms.admin.shared.ContentTypeProxy;
import com.nhim.cms.admin.shared.ElementDefinitionProxy;
import com.nhim.cms.admin.shared.NhimCMSAdminRequestFactory;

public class ContentTypeElementDefinitionSelection extends PopupPanel {

	private static ContentTypeElementDefinitionSelectionUiBinder uiBinder = GWT
			.create(ContentTypeElementDefinitionSelectionUiBinder.class);

	@UiTemplate("ContentTypeElementDefinitionSelection.ui.xml")
	interface ContentTypeElementDefinitionSelectionUiBinder extends
			UiBinder<Widget, ContentTypeElementDefinitionSelection> {
	}

	/**
	 * Custom listener for this widget.
	 */
	public interface Listener {
		void onSave();
	}

	private Listener listener;

	public void setListener(Listener listener) {
		this.listener = listener;
	}

	@UiField
	Button btnUp;
	@UiField
	Button btnDown;

	@UiField
	Button btnSave;
	@UiField
	Button btnCancel;
	@UiField
	Button btnGraterThan;
	@UiField
	Button btnLessThan;
	@UiField
	ListBox ltAvailableProp;
	@UiField
	ListBox ltSelectedProp;
	Map<Integer, String> selected = new HashMap<Integer, String>();
	Map<Integer, String> available = new HashMap<Integer, String>();
	ContentTypeProxy selectedContentTypeProxy;
	NhimCMSAdminRequestFactory requestFactory;
	private final ContentTypeElementDefinitionRPCServiceAsync service = GWT
			.create(ContentTypeElementDefinitionRPCService.class);

	public ContentTypeElementDefinitionSelection(
			ContentTypeProxy selectedContentTypeProxy,
			NhimCMSAdminRequestFactory requestFactory) {
		super(false, true);
		add(uiBinder.createAndBindUi(this));
		this.requestFactory = requestFactory;
		this.selectedContentTypeProxy = selectedContentTypeProxy;
		ltSelectedProp.setVisibleItemCount(15);
		ltSelectedProp.setWidth("16em");
		ltAvailableProp.setVisibleItemCount(15);
		ltAvailableProp.setWidth("16em");
		selected.clear();
		if (selectedContentTypeProxy != null) {
			service.findByContentTypeId(
					selectedContentTypeProxy.getId(),
					new AsyncCallback<ArrayList<ContentTypeElementDefinitionRPCProxy>>() {

						public void onFailure(Throwable e) {
							Window.alert("There was an error while fetching ContentTypes.");

						}

						public void onSuccess(
								ArrayList<ContentTypeElementDefinitionRPCProxy> results) {
							for (ContentTypeElementDefinitionRPCProxy proxy : results) {
								ltSelectedProp.addItem(proxy
										.getElementDefinitionName(), proxy
										.getElementDefinitionId().toString());
								selected.put(proxy.getElementDefinitionId(),
										proxy.getElementDefinitionName());
							}

						}
					});
		}
		// Request reports in the current range.
		Receiver<List<ElementDefinitionProxy>> elementDefinitionReceiver = new Receiver<List<ElementDefinitionProxy>>() {

			@Override
			public void onSuccess(List<ElementDefinitionProxy> result) {
				for (ElementDefinitionProxy ctProxy : result) {
					if (!selected.containsKey(ctProxy.getId())) {
						ltAvailableProp.addItem(ctProxy.getName(), ctProxy
								.getId().toString());
						available.put(ctProxy.getId(), ctProxy.getName());
					}

				}

			}
		};
		requestFactory.elementDefinitionRequest().findAll()
				.fire(elementDefinitionReceiver);
		ltAvailableProp.addDoubleClickHandler(new DoubleClickHandler() {

			public void onDoubleClick(DoubleClickEvent arg0) {
				Integer transferId = Integer.parseInt(ltAvailableProp
						.getValue(ltAvailableProp.getSelectedIndex()));
				selected.put(transferId, available.get(transferId));
				available.remove(transferId);
				rebindList();

			}
		});
		ltSelectedProp.addDoubleClickHandler(new DoubleClickHandler() {

			public void onDoubleClick(DoubleClickEvent arg0) {
				Integer transferId = Integer.parseInt(ltSelectedProp
						.getValue(ltSelectedProp.getSelectedIndex()));
				available.put(transferId, selected.get(transferId));
				selected.remove(transferId);
				rebindList();

			}
		});
	}

	private void rebindList() {
		ltAvailableProp.clear();
		ltSelectedProp.clear();
		for (Map.Entry<Integer, String> entry : selected.entrySet()) {
			ltSelectedProp.addItem(entry.getValue(), entry.getKey().toString());
		}
		for (Map.Entry<Integer, String> entry : available.entrySet()) {
			ltAvailableProp
					.addItem(entry.getValue(), entry.getKey().toString());
		}

	}

	@UiHandler("btnCancel")
	void handleButtonCancelClick(ClickEvent e) {
		this.hide();

	}

	@UiHandler("btnSave")
	void handleButtonSaveClick(ClickEvent e) {
		List<Integer> elementDefinitionIds = new ArrayList<Integer>();
		for (int i = 0; i < ltSelectedProp.getItemCount(); i++) {
			elementDefinitionIds.add(Integer.parseInt(ltSelectedProp
					.getValue(i)));
		}
		service.persitContentTypeElementDefinitioinsIdandPositionOnly(
				selectedContentTypeProxy.getId(), elementDefinitionIds,
				new AsyncCallback<Boolean>() {

					public void onFailure(Throwable arg0) {
						Window.alert("Error");

					}

					public void onSuccess(Boolean arg0) {
						if (listener != null) {
							listener.onSave();
						}

					}
				});
		this.hide();

	}

	private void moveUp() {
		int basePos = 0;
		for (int i = 0; i < ltSelectedProp.getItemCount(); i++) {

			if (ltSelectedProp.isItemSelected(i)) {
				if (i > basePos) {
					Integer currentId = Integer.parseInt(ltSelectedProp
							.getValue(i));
					String currentValue = ltSelectedProp.getItemText(i);
					ltSelectedProp.removeItem(i);
					ltSelectedProp.insertItem(currentValue,
							currentId.toString(), i - 1);
					ltSelectedProp.setItemSelected(i - 1, true);
					basePos = i - 1;
				} else {
					basePos = i + 1;
				}
			}
		}
	}

	private void moveDown() {
		int basePos = ltSelectedProp.getItemCount() - 1;
		for (int i = basePos; i >= 0; i--) {
			if (ltSelectedProp.isItemSelected(i)) {
				if (i < basePos) {
					Integer currentId = Integer.parseInt(ltSelectedProp
							.getValue(i));
					String currentValue = ltSelectedProp.getItemText(i);
					ltSelectedProp.removeItem(i);
					ltSelectedProp.insertItem(currentValue,
							currentId.toString(), i + 1);
					ltSelectedProp.setItemSelected(i + 1, true);
					basePos = i + 1;
				} else {
					basePos = i - 1;
				}
			}
		}

	}

	@UiHandler("btnUp")
	void handleButtonUpClick(ClickEvent e) {
		moveUp();
	}

	@UiHandler("btnDown")
	void handleButtonDownClick(ClickEvent e) {
		moveDown();
	}

	@UiHandler("btnGraterThan")
	void handleButtonGraterThanClick(ClickEvent e) {
		for (int i = 0; i < ltAvailableProp.getItemCount(); i++) {

			if (ltAvailableProp.isItemSelected(i)) {
				Integer transferId = Integer.parseInt(ltAvailableProp
						.getValue(i));
				selected.put(transferId, available.get(transferId));
				available.remove(transferId);
			}
		}
		rebindList();

	}

	@UiHandler("btnLessThan")
	void handleButtonLessThanClick(ClickEvent e) {
		for (int i = 0; i < ltSelectedProp.getItemCount(); i++) {

			if (ltSelectedProp.isItemSelected(i)) {
				Integer transferId = Integer.parseInt(ltSelectedProp
						.getValue(i));
				available.put(transferId, selected.get(transferId));
				selected.remove(transferId);
			}
		}
		rebindList();

	}

}
